import { dom } from '@knno/dom';
import { h, fragment } from '@knno/dom/jsx';
import { Cell, CellProps } from './cell';
export type TextCellProps = CellProps<TextCell, TextCellProps, string> & {
	multiline?: boolean;
	maxLength?: number;
};

export class TextCell extends Cell<TextCell, TextCellProps, string> {
	init() {
		this.addClass('text');
		if (!this.attrs.readonly) {
			this.attr('contenteditable', 'true');
		}
		this.text(this.getValue() ?? '');
		let imeInput = false;
		this.on('compositionstart', () => {
			imeInput = true;
		});
		this.on('compositionend', () => {
			imeInput = false;
		});
		this.on('keydown', (evt) => {
			if (evt.key === 'Enter' && this.attrs.multiline !== true) {
				evt.preventDefault();
			}

			const txt = this.text();
			const selection = window.getSelection();
			const range = selection?.getRangeAt(0);
			const selectedLength = range ? range.toString().length : 0;

			// Handle maxLength if specified
			if (this.attrs.maxLength && !evt.altKey && !evt.ctrlKey && !imeInput) {
				// Calculate new length considering selection replacement
				if (evt.key.length === 1 || evt.key === 'Enter') {
					const newLength = txt.length - selectedLength + 1;
					if (newLength > this.attrs.maxLength) {
						evt.preventDefault();
						return;
					}
				}
			}

			// Prevent newlines in single-line mode
			if (this.attrs.multiline !== true && evt.key === 'Enter') {
				evt.preventDefault();
			}
		});

		this.on('input', () => {
			let txt = this.text();
			if (imeInput) return;
			if (this.attrs.multiline !== true && /[\r\n]/.test(txt)) {
				txt = txt.replace(/[\r\n]/g, '');
				this.text(txt);
			}
			if (this.attrs.maxLength && txt.length > this.attrs.maxLength) {
				// Calculate new length considering selection replacement
				txt = txt.substring(0, this.attrs.maxLength);
				const selection = window.getSelection();
				const range = selection?.getRangeAt(0);
				const elem = this.elem();
				if (!range || !elem) return;
				const pos = range.endOffset;
				this.setValue(txt);
				if (pos < txt.length) {
					range.selectNodeContents(elem);
					range.setStart(range.startContainer.childNodes[0], pos);
					range.setEnd(range.startContainer, pos);
				} else {
					range.selectNodeContents(elem);
					range.collapse(false);
				}
				this.setValue(txt, { noUpdate: true });
			} else {
				this.setValue(txt, { noUpdate: true });
			}
		});
	}

	override text(): string;
	override text(value: string): this;
	override text(value?: string): string | this {
		if (value === undefined) {
			const elem = this.elem();
			if (!elem) return '';
			let txt = '';
			[...elem.childNodes].map((node) => {
				if (node.nodeType === Node.TEXT_NODE) {
					txt += node.textContent;
				} else if (node.nodeName === 'BR') {
					txt += '\n';
				} else if (node.nodeName === 'DIV' || node.nodeName === 'P') {
					txt += node.textContent + '\n';
				} else {
					txt += node.textContent;
				}
			});
			if (this.attrs.multiline !== true) {
				txt = txt.replace(/\n|\r/g, '');
			}
			return txt;
		} else {
			if (value === '') {
				this.html('');
			} else {
				const strs = value.split('\n');
				this.html('').append(
					...strs.map((str, idx) => {
						if (idx > 0) {
							return (
								<>
									<br />
									{str}
								</>
							);
						} else {
							return dom.text(str);
						}
					})
				);
			}
			return this;
		}
	}

	protected update(): void {
		this.text(this.getValue() ?? '');
	}
}
